/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version.  The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* OpenSceneGraph Public License for more details.
*/

#ifndef DB_FILENAMEUTILS
#define DB_FILENAMEUTILS 1

//#include <osgDB/Export>
#include "kernel/OgrePlatform.h"
#include "kernel/dll_cfg.h"
#include "kernel/string_def.h"

#include <string>
#include <vector>

namespace FD
{
	namespace Kernel
	{
		/** Gets the parent path from full name (Ex: /a/b/c.Ext => /a/b). */
		extern FD_Kernel_Export String getFilePath(const String& filename);
		/** Gets the extension without dot (Ex: /a/b/c.Ext => Ext). */
		extern FD_Kernel_Export String getFileExtension(const String& filename);
		/** Gets the extension including dot (Ex: /a/b/c.Ext => .Ext). */
		extern FD_Kernel_Export String getFileExtensionIncludingDot(const String& filename);
		/** Gets the lowercase extension without dot (Ex: /a/b/c.Ext => ext). */
		extern FD_Kernel_Export String getLowerCaseFileExtension(const String& filename);
		/** Gets file name with extension (Ex: /a/b/c.Ext => c.Ext). */
		extern FD_Kernel_Export String getSimpleFileName(const String& fileName);
		/** Gets file path without last extension (Ex: /a/b/c.Ext => /a/b/c ; file.ext1.ext2 => file.ext1). */
		extern FD_Kernel_Export String getNameLessExtension(const String& fileName);
		/** Gets file path without \b all extensions (Ex: /a/b/c.Ext => /a/b/c ; file.ext1.ext2 => file). */
		extern FD_Kernel_Export String getNameLessAllExtensions(const String& fileName);
		/** Gets file name without last extension (Ex: /a/b/c.Ext => c ; file.ext1.ext2 => file.ext1). */
		extern FD_Kernel_Export String getStrippedName(const String& fileName);
		/** If 'to' is in a subdirectory of 'from' then this function returns the subpath, otherwise it just returns the file name.
		* The function does \b not automagically resolve paths as the system does, so be careful to give canonical paths.
		* However, the function interprets slashes ('/') ans backslashes ('\') as they were equal.
		*/
		extern FD_Kernel_Export String getPathRelative(const String& from, const String& to);
		/** Gets root part of a path ("/" or "C:"), or an empty string if none found. */
		extern FD_Kernel_Export String getPathRoot(const String& path);
		/** Tests if path is absolute, as !getPathRoot(path).empty(). */
		extern FD_Kernel_Export bool isAbsolutePath(const String& path);


		/** Converts forward slashes (/) to back slashes (\). */
		extern FD_Kernel_Export String convertFileNameToWindowsStyle(const String& fileName);
		/** Converts back slashes (\) to forward slashes (/). */
		extern FD_Kernel_Export String convertFileNameToUnixStyle(const String& fileName);
		extern FD_Kernel_Export String convertToLowerCase(const String& fileName);

		const char UNIX_PATH_SEPARATOR = '/';
		const char WINDOWS_PATH_SEPARATOR = '\\';

		/** Get the path separator for the current platform. */
		extern FD_Kernel_Export char getNativePathSeparator();
		/** Check if the path contains only the current platform's path separators. */
		extern FD_Kernel_Export bool isFileNameNativeStyle(const String& fileName);
		/** Convert the path to contain only the current platform's path separators. */
		extern FD_Kernel_Export String convertFileNameToNativeStyle(const String& fileName);

		extern FD_Kernel_Export bool equalCaseInsensitive(const String& lhs,const String& rhs);
		extern FD_Kernel_Export bool equalCaseInsensitive(const String& lhs,const char* rhs);

		extern FD_Kernel_Export bool containsServerAddress(const String& filename);
		extern FD_Kernel_Export String getServerProtocol(const String& filename);
		extern FD_Kernel_Export String getServerAddress(const String& filename);
		extern FD_Kernel_Export String getServerFileName(const String& filename);

		/** Concatenates two paths */
		extern FD_Kernel_Export String concatPaths(const String& left, const String& right);

		/** Removes .. and . dirs in a path */
		extern FD_Kernel_Export String getRealPath(const String& path);

		/** Splits a path into elements between separators (including Windows' root, if any). */
		extern FD_Kernel_Export void getPathElements(const String& path, std::vector<String> & out_elements);

		/** Functor for helping sort filename in alphabetical and numerical order when using in conjunction with std::sort.*/
		struct FileNameComparator
		{
			inline bool operator() (const String& lhs, const String& rhs) const
			{
				String::size_type size_lhs = lhs.size();
				String::size_type size_rhs = rhs.size();
				String::size_type pos_lhs = 0;
				String::size_type pos_rhs = 0;
				while(pos_lhs<size_lhs && pos_rhs<size_rhs)
				{
					char c_lhs = lhs[pos_rhs];
					char c_rhs = rhs[pos_rhs];
					bool numeric_lhs = lhs[pos_lhs]>='0' && lhs[pos_lhs]<='9';
					bool numeric_rhs = rhs[pos_rhs]>='0' && rhs[pos_rhs]<='9';
					if (numeric_lhs && numeric_rhs)
					{
						String::size_type start_lhs = pos_lhs;
						++pos_lhs;
						while(pos_lhs<size_lhs && (lhs[pos_lhs]>='0' && lhs[pos_lhs]<='9')) ++pos_lhs;

						String::size_type start_rhs = pos_rhs;
						++pos_rhs;
						while(pos_rhs<size_rhs && (rhs[pos_rhs]>='0' && rhs[pos_rhs]<='9')) ++pos_rhs;

						if (pos_lhs<pos_rhs) return true;
						else if (pos_rhs<pos_lhs) return false;

						while(start_lhs<pos_lhs && start_rhs<pos_rhs)
						{
							if (lhs[start_lhs]<rhs[start_rhs]) return true;
							if (lhs[start_lhs]>rhs[start_rhs]) return false;
							++start_lhs;
							++start_rhs;
						}
					}
					else
					{
						if (c_lhs<c_rhs) return true;
						else if (c_rhs<c_lhs) return false;

						++pos_lhs;
						++pos_rhs;
					}
				}

				return pos_lhs<pos_rhs;
			}
		};
	}
}

#endif
